﻿Option Explicit On

'*******************************************************************
' Program: xmlVisio
' Author: Albert E Edlund
' Date:
'
' Purpose:
' Working with visio drawing in an xml format
'
'
'
'*******************************************************************

Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Text
Imports System.Text.StringBuilder

Imports Microsoft.Practices.EnterpriseLibrary.Common
Imports Microsoft.Practices.EnterpriseLibrary.Data
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling
Imports Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging

Imports System.IO
Imports System.Windows.Forms
Imports System.Xml
Imports System.Xml.Serialization
Imports System.Xml.Linq
Imports System.Xml.XPath

Imports <xmlns="http://schemas.microsoft.com/visio/2003/core">
Imports <xmlns:vx="http://schemas.microsoft.com/visio/2006/extension">
Imports <xmlns:v14="http://schemas.microsoft.com/office/visio/2010/extension">



Public Class frmDataMapping


#Region " Properties and Declarations "


    Private Enum DataType
        visPropTypeNumber = 2
        visPropTypeListFix = 1
        visPropTypeListVar = 4
        visPropTypeDate = 5
        visPropTypeCurrency = 7
        visPropTypeDuration = 6
        VisPropTypeString = 0
        visPropTypeBool = 3
    End Enum

    Private _dataPath As String
    Public Property dataPath As String
        Get
            dataPath = _dataPath
        End Get
        Set(value As String)
            _dataPath = value
        End Set
    End Property

    Public _xDoc As XDocument
    Public Property xDoc As XDocument
        Get
            Return Me._xDoc
        End Get
        Set(value As XDocument)
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "xDoc is Null.")
            End If
            Me._xDoc = value
        End Set
    End Property

    Private _lngRsId As Long
    Public Property lngRsId As Long
        Get
            lngRsId = _lngRsId
        End Get
        Set(value As Long)
            _lngRsId = value
        End Set
    End Property

    Private _lngRsConnId As Long
    Public Property lngRsConnId As Long
        Get
            lngRsConnId = _lngRsConnId
        End Get
        Set(value As Long)
            _lngRsConnId = value
        End Set
    End Property

    Private _strRsName As String
    Public Property strRsName As String
        Get
            strRsName = _strRsName
        End Get
        Set(value As String)
            _strRsName = value
        End Set
    End Property



    '
    ' dictionary of the pages
    '
    Private _dictPage As Dictionary(Of Long, String)
    Public Property dictPage As Dictionary(Of Long, String)
        Get
            Return Me._dictPage
        End Get
        Set(value As Dictionary(Of Long, String))
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "dictPage is Null.")
            End If
            Me._dictPage = value
        End Set
    End Property


    '
    '
    '
    Public Structure stcPageShape
        Dim psPage As Long
        Dim psShape As Long
    End Structure

    '
    '
    '
    Private _dictPageShape As Dictionary(Of stcPageShape, String)
    Public Property dictPageShape As Dictionary(Of stcPageShape, String)
        Get
            Return Me._dictPageShape
        End Get
        Set(value As Dictionary(Of stcPageShape, String))
            If (value Is Nothing) Then
                Throw New System.ArgumentNullException("Value", _
                    "dictPageShape is Null.")
            End If
            Me._dictPageShape = value
        End Set
    End Property


#End Region



    '
    ' build a dictionary where the key is a structure of pageId and shapeId and the value
    ' is the ShapeNameU
    '
    Public Sub buildPageShapeDict()

        Try

            _dictPage = Nothing
            dictPage = New Dictionary(Of Long, String)
            _dictPageShape = Nothing
            _dictPageShape = New Dictionary(Of stcPageShape, String)

            Dim qryPages = xDoc...<Page>
            Dim strPageNameU As String = "NoPageNameU"
            Dim lngPageID As Long

            Dim newPageShape As stcPageShape = New stcPageShape

            For Each page In qryPages

                Dim listOfPageAttributes As IEnumerable(Of XAttribute) = _
                    From attPage In page.Attributes _
                    Select attPage

                For Each attPage As XAttribute In listOfPageAttributes
                    Select Case LCase(attPage.Name.LocalName)
                        Case "id"
                            lngPageID = CLng(attPage.Value)
                        Case "nameu"
                            strPageNameU = CStr(attPage.Value)
                    End Select
                Next attPage

                ' put the pageid into the page dictionary
                If dictPage.ContainsKey(lngPageID) = False Then
                    dictPage.Add(lngPageID, strPageNameU)
                End If

                ' get the shapes for the page
                Dim qryShapes = page...<Shape>

                For Each shape In qryShapes

                    Dim lngShapeID As Long
                    Dim strShapeNameU As String = "NoShapeNameU"

                    Dim listOfShapeAttributes As IEnumerable(Of XAttribute) = _
                        From attShape In shape.Attributes _
                        Select attShape

                    For Each attShape As XAttribute In listOfShapeAttributes
                        Select Case LCase(attShape.Name.LocalName)
                            Case "id"
                                lngShapeID = CLng(attShape.Value)
                            Case "nameu"
                                strShapeNameU = CStr(attShape.Value)
                        End Select
                    Next attShape

                    With newPageShape
                        .psPage = lngPageID
                        .psShape = lngShapeID
                    End With

                    ' put the pageid into the pageshape dictionary
                    If dictPageShape.ContainsKey(newPageShape) = False Then
                        dictPageShape.Add(newPageShape, strShapeNameU)
                    End If

                Next shape
            Next page

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try
    End Sub


    '
    ' pass in a listview control and load it with the datarecordsets
    '
    Public Sub getDataRecordSets _
        (ByRef lvControl As ListView)

        If lvControl Is Nothing Then lvControl = Me.lvAdoRecordsets

        Try

            ' first check for a v2007/v12 implementation
            Dim qryRecordsets = Me.xDoc...<vx:DataRecordSet>
            Dim intRecordsets As Integer = qryRecordsets.Count

            lvControl.Items.Clear()
            lvControl.Columns.Clear()
            lvControl.View = View.Details
            lvControl.AllowColumnReorder = True
            lvControl.FullRowSelect = True
            lvControl.Columns.Add("Name", 100, HorizontalAlignment.Left)
            lvControl.Columns.Add("Id", 40, HorizontalAlignment.Right)
            lvControl.Columns.Add("ConnId", 40, HorizontalAlignment.Right)

            Dim lvItem As ListViewItem

            For Each recordset In qryRecordsets

                lngRsId = -1
                lngRsConnId = -1
                strRsName = "NoName"

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In recordset.Attributes() _
                    Select att

                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("{0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "id"
                            lngRsId = CLng(att.Value)
                        Case "name"
                            ' get the recordset name
                            strRsName = CStr(att.Value)
                        Case "connectionid"
                            lngRsConnId = CLng(att.Value)
                    End Select
                Next att

                lvItem = New ListViewItem(strRsName)
                lvItem.SubItems.Add(CStr(lngRsId))
                lvItem.SubItems.Add(CStr(lngRsConnId))

                ' add it to the listview on the data page
                lvControl.Items.Add(lvItem)

                ' get the first recordset table date
                If lvControl.Items.Count = 1 And _
                    lvControl.Name = "lvAdoRecordsets" Then

                    getDataColumnSet(recordset)
                    getRowMap(recordset, Me.lvRowMap)

                End If

            Next recordset


        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    ' read v2007 schema DataColumns query source is datarecordset
    '
    Private Sub getDataColumnSet(ByVal shapeSource As XElement)

        Try


            ' first check for a v2007/v12 implementation
            Dim qryDataColumns = shapeSource...<vx:DataColumns>
            Dim intDataColumns As Integer = qryDataColumns.Count

            For Each rsdataColumnset In qryDataColumns

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In rsdataColumnset.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    Console.WriteLine("Columns - {0}={1}", att.Name.LocalName, att.Value)
                Next att

                getDataColumn(rsdataColumnset, Me.lvColumns)

            Next rsdataColumnset

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    ' read v2007 schema DataColumns query source is datacolumnset
    '
    Private Sub getDataColumn _
        (ByVal shapeSource As XElement, _
         ByRef lvControl As ListView)

        If lvControl Is Nothing Then lvControl = Me.lvColumns


        Try


            ' first check for a v2007/v12 implementation
            Dim qryDataColumn = shapeSource...<vx:DataColumn>
            Dim intDataColumn As Integer = qryDataColumn.Count

            Dim lvItem As ListViewItem

            lvControl.Items.Clear()
            lvControl.Columns.Clear()
            lvControl.View = View.Details
            lvControl.AllowColumnReorder = True
            lvControl.FullRowSelect = True
            lvControl.Columns.Add("Name", 200, HorizontalAlignment.Left)
            lvControl.Columns.Add("Label", 100, HorizontalAlignment.Left)
            lvControl.Columns.Add("DataType", 80, HorizontalAlignment.Left)
            lvControl.Columns.Add("DispOrd", 40, HorizontalAlignment.Right)

            For Each rsdataColumn In qryDataColumn

                Dim strName As String = ""
                Dim strLabel As String = ""
                ' default datatype is string
                Dim strDataType As String = "string"
                Dim strDisplayOrder As String = ""

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In rsdataColumn.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("Column {0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "name"
                            strName = CStr(att.Value)
                        Case "label"
                            strLabel = CStr(att.Value)
                        Case "datatype"
                            strDataType = DataTypeToStr(CInt(att.Value))
                        Case "displayorder"
                            strDisplayOrder = CStr(att.Value)
                    End Select
                Next att

                ' add it to the listview control
                lvItem = New ListViewItem(strName)
                lvItem.SubItems.Add(strLabel)
                lvItem.SubItems.Add(strDataType)
                lvItem.SubItems.Add(strDisplayOrder)

                ' add it to the listview on the data page
                lvControl.Items.Add(lvItem)

            Next rsdataColumn

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    '
    '
    Private Function DataTypeToStr(ByVal intDataType As Integer) As String

        Dim strDataType As String = ""

        If intDataType = DataType.visPropTypeBool Then
            strDataType = "bool"
        ElseIf intDataType = DataType.visPropTypeCurrency Then
            strDataType = "currency"
        ElseIf intDataType = DataType.visPropTypeDate Then
            strDataType = "date"
        ElseIf intDataType = DataType.visPropTypeDuration Then
            strDataType = "duration"
        ElseIf intDataType = DataType.visPropTypeListFix Then
            strDataType = "listfix"
        ElseIf intDataType = DataType.visPropTypeListVar Then
            strDataType = "listvar"
        ElseIf intDataType = DataType.visPropTypeNumber Then
            strDataType = "number"
        ElseIf intDataType = DataType.VisPropTypeString Then
            strDataType = "string"
        Else
            strDataType = "???"
        End If

        DataTypeToStr = strDataType

    End Function

    '
    ' read v2007 schema DataColumns query source is datarecordset
    '
    Private Sub getRowMap _
        (ByVal shapeSource As XElement, _
         ByRef lvControl As ListView)

        If lvControl Is Nothing Then lvControl = Me.lvRowMap

        Try


            ' first check for a v2007/v12 implementation
            Dim qryRowMap = shapeSource...<vx:RowMap>
            Dim intRowMap As Integer = qryRowMap.Count


            lvControl.Items.Clear()
            lvControl.Columns.Clear()
            lvControl.View = View.Details
            lvControl.AllowColumnReorder = True
            lvControl.FullRowSelect = True
            lvControl.Columns.Add("RowId", 40, HorizontalAlignment.Right)
            lvControl.Columns.Add("PageId", 40, HorizontalAlignment.Right)
            lvControl.Columns.Add("PageName", 100, HorizontalAlignment.Left)
            lvControl.Columns.Add("ShapeId", 40, HorizontalAlignment.Right)
            lvControl.Columns.Add("ShapeNameU", 100, HorizontalAlignment.Left)

            Dim currPageShape As stcPageShape = New stcPageShape
            Dim lvItem As ListViewItem

            For Each rsdataRowMap In qryRowMap

                Dim strRowId As String = "-1"
                Dim strPageId As String = "-1"
                Dim strPageNameU As String = "NoPgNameU"
                Dim strShapeId As String = "-1"
                Dim strShapeNameU As String = "NoShpNameU"

                Dim listOfAttributes As IEnumerable(Of XAttribute) = _
                    From att In rsdataRowMap.Attributes() _
                    Select att
                For Each att As XAttribute In listOfAttributes
                    ' Console.WriteLine("{0}={1}", att.Name.LocalName, att.Value)
                    Select Case LCase(att.Name.LocalName)
                        Case "rowid"
                            strRowId = CStr(att.Value)
                        Case "pageid"
                            strPageId = CStr(att.Value)
                        Case "shapeid"
                            strShapeId = CStr(att.Value)
                    End Select
                Next att

                With currPageShape
                    .psPage = CLng(strPageId)
                    .psShape = CLng(strShapeId)
                End With

                If dictPage.ContainsKey(CLng(strPageId)) = True Then
                    strPageNameU = dictPage(CLng(strPageId)).ToString
                End If

                If dictPageShape.ContainsKey(currPageShape) = True Then
                    strShapeNameU = dictPageShape(currPageShape).ToString
                Else
                    strShapeNameU = "ShapeNotFound"
                End If

                lvItem = New ListViewItem(strRowId)
                lvItem.SubItems.Add(strPageId)
                lvItem.SubItems.Add(strPageNameU)
                lvItem.SubItems.Add(strShapeId)
                lvItem.SubItems.Add(strShapeNameU)

                ' add it to the listview on the data page
                lvControl.Items.Add(lvItem)

            Next rsdataRowMap

        Catch errXml As XmlException
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(errXml, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        Catch err As Exception
            Dim rethrow As Boolean = ExceptionPolicy.HandleException(err, "Log Only Policy")
            If (rethrow) Then
                Throw
            End If
        End Try

    End Sub

    '
    '
    '
    Private Sub lvAdoRecordsets_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles lvAdoRecordsets.SelectedIndexChanged
    
        Dim rsItems As ListView.SelectedListViewItemCollection = lvAdoRecordsets.SelectedItems
        Dim rsItem As ListViewItem
        Dim rsSubItem As ListViewItem.ListViewSubItem

        If 0 < rsItems.Count Then
            rsItem = rsItems(0)

            ' query the recordsets
            Dim qryRecordset = From rsSel In Me.xDoc...<vx:DataRecordSet>
                Where (rsSel.@ID = rsItem.SubItems(1).Text)

            If qryRecordset.Count = 1 Then
                getDataColumnSet(qryRecordset.First)
                getRowMap(qryRecordset.First, Me.lvRowMap)

            Else
                MsgBox("could not find recordset")
            End If ' test that only one recordset was found

        End If

    End Sub

    '
    '
    '
    Private Sub ExitToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        Me.Close()
    End Sub

    '
    '
    '
    Private Sub AboutToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        frmAbout.ShowDialog()
    End Sub

    '
    '
    '
    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

        _dictPage = Nothing
        dictPage = New Dictionary(Of Long, String)
        _dictPageShape = Nothing
        _dictPageShape = New Dictionary(Of stcPageShape, String)

    End Sub

End Class